/**
 *  @file
 *  @brief   四边形壳单元
 *  @author  wanghuan
 *  @date    2024.03.07
 *  @version  v1.0
 *  @par Copyright(c):  ShenGong  Simulation corporation
 */

#pragma once
#include "Utility/Algebra/Matrix.h"

#include "DataStructure/Input/Element/CQUAD4Data.h"
#include "DataStructure/Result/ElementalForce/QUAD4ForceData.h"

#include "SGFem/Integration/IntegrationFormula/Gauss2D1X1P.h"
#include "SGFem/Integration/ShapeFunction/Plane4NodeIncomShpFunc.h"
#include "SGFem/ElementCalculator/Interface/IElementCalculator.h"
#include "SGFem/PublicElement/Common/PublicElementExport.h"
#include "SGFem/PublicElement/Membrane/Quad4SmallDrillMem.h"
#include "SGFem/PublicElement/Plate/MITC4PlateCalculator.h"

SG_FEMSOLVER_ELEMENT_NAMESPACE_OPEN
/** @brief 壳单元单元矩阵计算器
 *
 * 单元具有四个节点， 每个节点具有6个自由度。能够负载面内膜变形以及
 * 面外的弯曲和剪切变形。
 */
class PublicElement_DECLSPEC Quad4ShellCalculator : public SG::FEMSolver::Element::IElementCalculator
{
  public:
    Quad4ShellCalculator ()          = default;
    virtual ~Quad4ShellCalculator () = default;

    /** @brief 单元刚度矩阵计算
     * @param [in]  cquad4       单元数据
     * @param [in]  coord        单元局部坐标
     * @param [in]  SecConstant  单元局部坐标系下的材料刚度
     * @param [in]  Tele         单元刚度从单元局部坐标到 位移输出坐标下的变换矩阵
     * @param [in]  Tw           翘曲修正矩阵
     * @param [out] kg           单元全局坐标下刚度矩阵
     */
    void ComputeStiffness (const SG::DataStructure::FEM::CQUAD4Data&               cquad4,
                           const SG::Algebra::Matrix&                              coord,
                           const SG::DataStructure::FEM::ShellSecMaterialConstant& secConstant,
                           const SG::Algebra::Matrix&                              Tele,
                           const SG::DataStructure::Common::Real&                  zWarp,
                           SG::Algebra::Matrix& _OUT                               kg) const;

    /** @brief 单元质量矩阵计算
     * @param [in]  coord        单元局部坐标
     * @param [in]  arealDensity 面密度(密度乘以厚度)
     * @param [in]  coupled      true 计算耦合质量矩阵；否则计算集中质量矩阵
     * @param [out] MassMatrix   单元全局坐标下刚度矩阵
     */
    void ComputeMassMatrix (const SG::Algebra::Matrix&            coord,
                            const SG::DataStructure::Common::Real arealDensity,
                            bool                                  coupled,
                            SG::Algebra::Matrix& _OUT             MassMatrix) const;
    /**
     * @brief    计算单元中面和上下表面积分点应变
     * 
     * @param    memDisplacement 
     * @param    plateDisplacement 
     * @param    thickness 
     * @param    cm 
     * @param    localCoord 
     * @param    strainM 
     * @param    strainT 
     * @param    strainB 
     * @param    onlyMid 是否只计算中面
     * @author   wanghuan
     * @date     2025.03.08
     */
    void ComputeIntegStrain (const SG::Algebra::Matrix&             memDisplacement,
                             const SG::Algebra::Matrix&             plateDisplacement,
                             const SG::DataStructure::Common::Real* thickness,
                             const SG::Algebra::Matrix&             cm,
                             const SG::Algebra::Matrix&             localCoord,
                             SG::Algebra::Matrix& _OUT              strainM,
                             SG::Algebra::Matrix& _OUT              strainT,
                             SG::Algebra::Matrix& _OUT              strainB,
                             bool                                   onlyMid = true);

    void ComputeinternalForces (const SG::Algebra::Matrix&                    memDisplacement,
                                const SG::Algebra::Matrix&                    plateDisplacement,
                                const SG::Algebra::Matrix&                    localCoord,
                                const SG::Algebra::Matrix&                    Cm,
                                const SG::DataStructure::Common::Real* const  thickness,
                                SG::DataStructure::Post::QUAD4ForceData& _OUT internalForces);

    virtual void               Initialize (SG::DataStructure::FEM::ElementTypes type) override;
    virtual void               ComputeElementMatries (const SG::DBManager::DBServiceFactorySP dbServiceFactory) override;
    virtual void               DataRecovery (const SG::DBManager::DBServiceFactorySP             dbServiceFactory,
                                             int                                                 subcaseId,
                                             SG::DataStructure::Common::Real time,
                                             const std::vector<SG::DataStructure::Common::Real>& globalDisplacement) override;
    virtual void               ComputeStressStiffness (const SG::DBManager::DBServiceFactorySP dbServiceFactory, int staticSubId) override;
    static ElementCalculatorSP Create ()
    {
        return std::make_shared<Quad4ShellCalculator> ();
    }

  private:
    SG::DataStructure::FEM::ElementTypes m_type;
    SG::FEMSolver::Element::Gauss2D2X2P  m_integForm;

    SG::FEMSolver::Element::Plane4NodeShpFunc m_shpFunc;
    SG::FEMSolver::Element::Plane4NodeShpFunc m_shpFunc0;  ///< 中心点形函数

    // ToDo 考虑替换成基类的指针
    Quad4SmallDrillMem   m_mem;
    MITC4PlateCalculator m_plate;
};

SG_FEMSOLVER_ELEMENT_NAMESPACE_CLOSE